package com.haltakov.letterjumble.game.api;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Board {
	
	private int countX;
	private int countY;
	
	private CellType cellTypes[][];
	private Letter cells[][];
	
	private boolean isEmpty = true;

	public Board(String boardFile) throws BoardFileException {
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			Document doc = factory.newDocumentBuilder().parse(boardFile);
			
			XMLHelpers.removeWhitespaceNodes(doc.getDocumentElement());
			
			countX = Integer.parseInt(doc.getElementsByTagName("sizex").item(0).getTextContent());
			countY = Integer.parseInt(doc.getElementsByTagName("sizex").item(0).getTextContent());
			
			cellTypes = new CellType[countX][countY];
			cells = new Letter[countX][countY];
			
			for (int i=0; i<countY; ++i) 
				for (int j=0; j<countX; ++j)
					cellTypes[i][j] = CellType.NORMAL;
			
			NodeList cellList = doc.getElementsByTagName("cell");
			for (int i=0; i<cellList.getLength(); ++i) {
				Node c = cellList.item(i);
				NamedNodeMap pos = c.getAttributes();
				int xx = Integer.parseInt(pos.getNamedItem("x").getTextContent())-1;
				int yy = Integer.parseInt(pos.getNamedItem("y").getTextContent())-1;
				
				String type = cellList.item(i).getTextContent();
				if (type.equals("W3"))
					cellTypes[xx][yy] = CellType.WORDx3;
				else if (type.equals("W2"))
					cellTypes[xx][yy] = CellType.WORDx2;
				else if (type.equals("L3"))
					cellTypes[xx][yy] = CellType.LETTERx3;
				else if (type.equals("L2"))
					cellTypes[xx][yy] = CellType.LETTERx2;
				else if (type.equals("S"))
					cellTypes[xx][yy] = CellType.START;
			}
						
		} catch (SAXException e) {
			throw new BoardFileException("Cannot parse board file!");
		} catch (IOException e) {
			throw new BoardFileException("Cannot load board file!");
		} catch (ParserConfigurationException e) {
			throw new BoardFileException("Cannot parse board file!");
		}	
	}

	public CellIterator iterator() {
		return null;
	}
	
	public Letter getLetter(int x, int y) {
		 if (cells[x][y] == null)
			 return null;
		 else
			 return cells[x][y];
	}

	public CellType getCellType(int x, int y) {
		return cellTypes[x][y];
	}

	public boolean checkWordPlacement(BoardWord word) {
		int overlapping = 0;
		int x = word.getX();
		int y = word.getY();
		
		if ((word.getDirection() == WordDirection.HORIZONTAL && x+word.getSize() > countX) ||
			(word.getDirection() == WordDirection.HORIZONTAL && y+word.getSize() > countY) ||
			(x < 0) || (y < 0))
			return false;
		
		for (Letter l: word.getLetters()) {
			if (cells[x][y] != null) {
				++overlapping;
				if (!cells[x][y].equals(l))
					return false;
			}
			else if (cellTypes[x][y] == CellType.START)
				++overlapping;
			else {
				if (word.getDirection() == WordDirection.HORIZONTAL) {
					if ((y != 0 && cells[x][y-1] != null) || (y != countY-1 && cells[x][y+1] != null))
						return false;
				}
				else {
					if ((x != 0 && cells[x-1][y] != null) || (x != countX-1 && cells[x+1][y] != null))
						return false;
				}
			}
			
			if (word.getDirection() == WordDirection.HORIZONTAL)
				++x;
			else
				++y;
		}
		
		return ((overlapping > 0) && (overlapping < word.getSize()));
	}
	
	public boolean isEmpty() {
		return isEmpty;
	}
	
	public void placeWord(BoardWord word) {
		isEmpty = false;
		
		int x = word.getX();
		int y = word.getY();
		
		int xd = 0, yd = 0;
		if (word.getDirection() == WordDirection.HORIZONTAL)
			xd = 1;
		else
			yd = 1;
		
		for (Letter l: word.getLetters()) {
			cells[x][y] = l;
			x += xd;
			y += yd;
		}
	}
	
	public int getWordPoints(BoardWord word) {
		int result = 0;
		int x = word.getX();
		int y = word.getY();
		
		boolean wordX2 = false, wordX3 = false;
		
		for (Letter l: word.getLetters()) {
			if (cells[x][y] == null) {
				switch (cellTypes[x][y]) {
				case LETTERx2: result += 2*l.getPoints(); break;
				case LETTERx3: result += 3*l.getPoints(); break;
				case WORDx2: wordX2 = true; break;
				case WORDx3: wordX3 = true; break;
				default: result += l.getPoints();
				}
			}
			else
				result += l.getPoints();
				
			if (word.getDirection() == WordDirection.HORIZONTAL)
				++x;
			else
				++y;
		}
		
		if (wordX3)
			result *= 3;
		if (wordX2)
			result *= 2;
				
		return result;
	}
	
	public void setCells (Letter cells[][]) {
		this.cells = cells;
	}
	
	public void clear() {
		for (int i=0; i<countX; ++i)
			for (int j=0; j<countY; ++j)
				cells[i][j] = null;
		
		isEmpty = true;
	}

	public int getCountX() {
		return countX;
	}

	public int getCountY() {
		return countY;
	}
}
